#pragma once

#include <memory>
#include <mutex>
#include <functional>
#include <utility>

template<typename T>
class Mutexed {
private:
    std::mutex mutex_;
    T data_;

    explicit Mutexed(T data) : data_(std::move(data)) {}  // Mutex构造函数

    template<typename T_, typename U>
    friend std::shared_ptr<Mutexed<T_>> make_mutex(U&& x);

public:
    // 不允许拷贝 因为如果拷贝的话会复制里面的mutex，失去了保护意义
    Mutexed(const Mutexed&) = delete;
    Mutexed& operator=(const Mutexed&) = delete;

    // 允许移动
    Mutexed(Mutexed&&) = default;
    Mutexed& operator=(Mutexed&&) = default;

    // 戴锁操作
    template<typename F>
    void with_lock(F&& func) {
        std::lock_guard<std::mutex> lock(mutex_);
        func(data_);
    }


    // 下面是rust风味cpp 好好品尝罢
    class Guard {
        std::lock_guard<std::mutex> lock_;
        T& data_;

        friend class Mutexed; // 只有 Mutex 能构造 Guard
        Guard(std::mutex& mtx, T& data) noexcept : lock_(mtx), data_(data) {}

    public:
        // 禁止拷贝和移动 Guard，确保锁的唯一性
        Guard(const Guard&) = delete;
        Guard& operator=(const Guard&) = delete;
        Guard(Guard&&) = delete;
        Guard& operator=(Guard&&) = delete;

        // 提供对内部数据的引用
        T* operator->() { return &data_; }
        T& operator*() { return data_; }
    };

    // 返回一个天然带锁的线程守卫
    Guard lock() {
        return Guard(mutex_, data_);
    }
};


// 工厂函数 Mutex类只能从这里获得！别的获得办法不允许！
template<typename T_, typename U>
std::shared_ptr<Mutexed<T_>> make_mutex(U&& x) {
    // ReSharper disable once CppSmartPointerVsMakeFunction
    return std::shared_ptr<Mutexed<T_>>(new Mutexed<T_>(std::forward<U>(x)));
}